package com.zhiyin.game.Service;

import com.zhiyin.game.bean.Cell;
import com.zhiyin.game.bean.Vector2;
import org.springframework.stereotype.Component;

import java.util.*;

@Component
public class CellService {

    //数值越高，墙越多
    private static float flexible = 0.7f;

    /**
     * 填充墙的数据
     * @param width  生成地图宽度
     * @param height  生成地图高度
     * @param map    地图数据
     * @return
     */
    public Cell[][] initCellData(int width, int height, Cell[][] map) {
        Random random = new Random();
        int posX = 0;
        int posY = 0;
        getCell(map, posX, posY).setVisited(true);
        Stack<Vector2> stack = new Stack();
        stack.push(new Vector2(posX, posY));
        while (stack.size() > 0) {
            List<String> moveDir = new ArrayList<>();
            List<String> removeDir = new ArrayList<>();
            if (posX > 0 && !getCell(map, posX - 1, posY).isVisited())
                moveDir.add("L");
            if (posX < width - 1 && !getCell(map, posX + 1, posY).isVisited())
                moveDir.add("R");
            if (posY < height - 1 && !getCell(map, posX, posY + 1).isVisited())
                moveDir.add("D");
            if (posY > 0 && !getCell(map, posX, posY - 1).isVisited())
                moveDir.add("U");

            if (posX > 0)
                removeDir.add("L");
            if (posX < width - 1)
                removeDir.add("R");
            if (posY < height - 1)
                removeDir.add("D");
            if (posY > 0)
                removeDir.add("U");

            if (moveDir.size() > 0) {
                String dir = moveDir.get(random.nextInt(moveDir.size()));
                stack.push(new Vector2(posX, posY));
                switch (dir) {
                    case "L":
                        getCell(map, posX, posY).setLeftWall(false);
                        getCell(map, posX, posY).setVisited(true);
                        getCell(map, posX - 1, posY).setRightWall(false);
                        posX -= 1;
                        break;
                    case "R":
                        getCell(map, posX, posY).setRightWall(false);
                        getCell(map, posX, posY).setVisited(true);
                        getCell(map, posX + 1, posY).setLeftWall(false);
                        posX += 1;
                        break;
                    case "D":
                        getCell(map, posX, posY).setBottomWall(false);
                        getCell(map, posX, posY).setVisited(true);
                        getCell(map, posX, posY + 1).setTopWall(false);
                        posY += 1;
                        break;
                    case "U":
                        getCell(map, posX, posY).setTopWall(false);
                        getCell(map, posX, posY).setVisited(true);
                        getCell(map, posX, posY - 1).setBottomWall(false);
                        posY -= 1;
                        break;
                }
            } else {
                getCell(map, posX, posY).setVisited(true);
                Vector2 lastPos = stack.pop();
                if (Math.random() > flexible) {
                    for (int i = 0; i < random.nextInt(2) + 1; i++) {
                        switch (removeDir.get(random.nextInt(removeDir.size()))) {
                            case "L":
                                getCell(map, posX, posY).setLeftWall(false);
                                getCell(map, posX - 1, posY).setRightWall(false);
                                break;
                            case "R":
                                getCell(map, posX, posY).setRightWall(false);
                                getCell(map, posX + 1, posY).setLeftWall(false);
                                break;
                            case "D":
                                getCell(map, posX, posY).setBottomWall(false);
                                getCell(map, posX, posY + 1).setTopWall(false);
                                break;
                            case "U":
                                getCell(map, posX, posY).setTopWall(false);
                                getCell(map, posX, posY - 1).setBottomWall(false);
                                break;
                        }
                    }
                }
                posX = lastPos.getX();
                posY = lastPos.getY();
            }
        }
        return map;
    }

    private Cell getCell(Cell[][] map, int x, int y) {
        return map[x][y];
    }
}
